﻿using System.Linq;
using NUnit.Framework;
using StreetPacMan.Server.Facade;
using System.Collections.Generic;
using StreetPacMan.Server.Rules;

namespace StreetPacMan.Server.Tests.Integ
{
    [TestFixture]
    public class PacManGhostCollision : BaseCleaner
    {
        [Test]
        public void PollServer_AsPacMan_NearGhostLocation_WithOtherPacMenOnBoard_MessageShouldBePacManWasEaten()
        {
            var instance = ServerFacadeFactory.GetServerFacade();

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);
            var pacman2 = instance.JoinGameX("GameName", "PacManName2", PlayerRole.PacMan);
            var ghost = instance.JoinGameX("GameName", "Ghost1", PlayerRole.Ghost);
            instance.UpdateMyWhereabouts(new ServerPollParameters(ghost.PlayerId, 20, 20, true));
            var pacManResult = instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 20.00001, 20.00001, true));

            Assert.AreEqual("Ghost Ghost1 ate PacMan PacManName", pacManResult.RecentMessages.Last().Body);
            Assert.IsTrue(pacManResult.Players.Where(x => x.EntityId == pacman.PlayerId).IsEmptyX());
            Assert.IsTrue(pacManResult.Players.Where(x => x.EntityId == ghost.PlayerId).HasElementsX());
        }

        [Test]
        public void PollServer_AsGhost_NearPacManLocation_WithOtherPacMenOfBoard_MessageShouldBePacManWasEaten()
        {
            var instance = ServerFacadeFactory.GetServerFacade();

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);
            var pacman2 = instance.JoinGameX("GameName", "PacManName2", PlayerRole.PacMan);
            var ghost = instance.JoinGameX("GameName", "Ghost1", PlayerRole.Ghost);
            var pacManResult = instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 20.00001, 20.00001, true));
            var ghostResult = instance.UpdateMyWhereabouts(new ServerPollParameters(ghost.PlayerId, 20, 20, true));

            Assert.AreEqual("Ghost Ghost1 ate PacMan PacManName", ghostResult.RecentMessages.Last().Body);
            Assert.IsTrue(ghostResult.Players.Where(x => x.EntityId == pacman.PlayerId).IsEmptyX());
            Assert.IsTrue(ghostResult.Players.Where(x => x.EntityId == ghost.PlayerId).HasElementsX());
        }

        [Test]
        public void PollServer_AsLastPacManOnBoard_NearGhostLocation_MessageShouldBeGameOver()
        {
            var instance = ServerFacadeFactory.GetServerFacade();

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);
            var ghost = instance.JoinGameX("GameName", "Ghost1", PlayerRole.Ghost);
            instance.UpdateMyWhereabouts(new ServerPollParameters(ghost.PlayerId, 20, 20, true));
            var pacManResult = instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 20.00001, 20.00001, true));

            Assert.AreEqual("Game Over. Ghost Ghost1 ate the last PacMan PacManName. Ghosts win!", pacManResult.RecentMessages.Last().Body);
        }

        [Test]
        public void PollServer_AsGhost_NearLastPacManOnBoard_MessageShouldBeGameOver()
        {
            var instance = ServerFacadeFactory.GetServerFacade();

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);
            var ghost = instance.JoinGameX("GameName", "Ghost1", PlayerRole.Ghost);
            var pacManResult = instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 20.00001, 20.00001, true));
            var ghostResult = instance.UpdateMyWhereabouts(new ServerPollParameters(ghost.PlayerId, 20, 20, true));

            Assert.AreEqual("Game Over. Ghost Ghost1 ate the last PacMan PacManName. Ghosts win!", ghostResult.RecentMessages.Last().Body);
        }


        [Test]
        public void PollServer_AsPacMan_NearGhostLocation_AfterEatingNormalApple_MessageShouldBeGameOver()
        {
            var instance = ServerFacadeFactory.CreateGameWithExtraApplesAt(new InitialApple { Lat = 20.00001, Lon = 20.00001, Type = AppleKind.Normal });

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);
            var ghost = instance.JoinGameX("GameName", "Ghost1", PlayerRole.Ghost);
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 21, 21, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(ghost.PlayerId, 20, 20, true));
            var pacManResult = WalkPlayerTo(20, 20, pacman.PlayerId, instance);

            Assert.AreEqual("Game Over. Ghost Ghost1 ate the last PacMan PacManName. Ghosts win!", pacManResult.RecentMessages.Last().Body);
        }

        [Test]
        public void PollServer_AsPacMan_NearGhostLocation_AfterEatingSuperApple_MessageShouldBePacManAteGhost()
        {
            var instance = ServerFacadeFactory.CreateGameWithExtraApplesAt(new InitialApple { Lat = 20.00001, Lon = 20.00001, Type = AppleKind.Super });

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);
            var ghost = instance.JoinGameX("GameName", "Ghost1", PlayerRole.Ghost);
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 21, 21, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(ghost.PlayerId, 20, 20, true));
            var pacManResult = WalkPlayerTo(20, 20, pacman.PlayerId, instance);

            Assert.AreEqual("PacMan PacManName ate ghost Ghost1", pacManResult.RecentMessages.Last().Body);
        }

        [Test]
        public void PollServer_AsPacMan_NearGhostLocation_AfterEatingSuperApple_ScoreShouldBe200PointMore()
        {
            var instance = ServerFacadeFactory.CreateGameWithExtraApplesAt(new InitialApple { Lat = 20.00001, Lon = 20.00001, Type = AppleKind.Super });

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);
            var ghost = instance.JoinGameX("GameName", "Ghost1", PlayerRole.Ghost);
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 20, 20, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(ghost.PlayerId, 21, 21, true));
            int earlyScore = instance.GetGameStateAsObvserverX("GameName").Score;
            WalkPlayerTo(21, 21, pacman.PlayerId, instance);
            int lateScore = instance.GetGameStateAsObvserverX("GameName").Score;

            Assert.AreEqual(earlyScore + AddScoreIfPacManAteGhostRule.ScoreForEatingGhost, lateScore);
        }

        private ServerPollResult WalkPlayerTo(double lat, double lon, int playerId, IServerFacade instance)
        {
            instance.UpdateMyWhereabouts(new ServerPollParameters(playerId, lat - 0.000001, lon - 0.000001, true));
            return instance.UpdateMyWhereabouts(new ServerPollParameters(playerId, lat, lon, true));
        }


        [Test]
        public void PollServer_AsSuperPacMan_AfterEatingGhost_ShouldNotAddTheScoreAgain()
        {
            var instance = ServerFacadeFactory.CreateGameWithExtraApplesAt(new InitialApple { Lat = 20.00001, Lon = 20.00001, Type = AppleKind.Super });

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);
            var ghost = instance.JoinGameX("GameName", "Ghost1", PlayerRole.Ghost);
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 20, 20, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(ghost.PlayerId, 21, 21, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 21, 21, true));
            int lateScore = instance.GetGameStateAsObvserverX("GameName").Score;
            instance.UpdateMyWhereabouts(new ServerPollParameters(ghost.PlayerId, 21, 21, true));
            int laterScore = instance.GetGameStateAsObvserverX("GameName").Score;

            Assert.AreEqual(lateScore, laterScore);
        }
    }
}